package com.dong.oss.service;

import com.aliyun.oss.OSS;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.dong.oss.config.OssProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.Tika;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.InputStream;
import java.util.Optional;

/**
 * 阿里云OSS服务类
 */
@Slf4j
@Service
public class OssService {
    
    private final Optional<OSS> ossClient;
    private final OssProperties ossProperties;
    private final Tika tika = new Tika();
    
    public OssService(@Autowired(required = false) OSS ossClient, OssProperties ossProperties) {
        this.ossClient = Optional.ofNullable(ossClient);
        this.ossProperties = ossProperties;
    }
    
    /**
     * 检查OSS客户端是否可用
     */
    private void checkClientAvailable() {
        if (!ossClient.isPresent()) {
            throw new RuntimeException("OSS客户端未配置或配置不正确，请检查application.yaml中的oss配置");
        }
    }
    
    /**
     * 上传对象到OSS
     * 
     * @param objectName 对象名称
     * @param inputStream 输入流
     * @param contentLength 内容长度
     * @return 上传结果
     */
    public boolean uploadObject(String objectName, InputStream inputStream, long contentLength) {
        checkClientAvailable();
        try {
            // 检测文件类型
            String contentType = detectContentType(objectName);
            
            // 设置对象元数据
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(contentLength);
            metadata.setContentType(contentType);
            
            // 创建上传请求
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    ossProperties.getBucketName(),
                    objectName,
                    inputStream,
                    metadata
            );
            
            // 执行上传
            PutObjectResult result = ossClient.get().putObject(putObjectRequest);
            
            log.info("成功上传对象到OSS: {}，ETag: {}", objectName, result.getETag());
            return true;
        } catch (Exception e) {
            log.error("上传对象到OSS失败: {}", objectName, e);
            return false;
        }
    }
    
    /**
     * 上传对象到OSS（带重命名）
     * 
     * @param sourceObjectName 源对象名称
     * @param targetObjectName 目标对象名称
     * @param inputStream 输入流
     * @param contentLength 内容长度
     * @return 上传结果
     */
    public boolean uploadObject(String sourceObjectName, String targetObjectName, InputStream inputStream, long contentLength) {
        checkClientAvailable();
        try {
            // 检测文件类型
            String contentType = detectContentType(sourceObjectName);
            
            // 设置对象元数据
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(contentLength);
            metadata.setContentType(contentType);
            
            // 添加自定义元数据
            metadata.addUserMetadata("source-object", sourceObjectName);
            metadata.addUserMetadata("migration-time", String.valueOf(System.currentTimeMillis()));
            
            // 创建上传请求
            PutObjectRequest putObjectRequest = new PutObjectRequest(
                    ossProperties.getBucketName(),
                    targetObjectName,
                    inputStream,
                    metadata
            );
            
            // 执行上传
            PutObjectResult result = ossClient.get().putObject(putObjectRequest);
            
            log.info("成功上传对象到OSS: {} -> {}，ETag: {}", sourceObjectName, targetObjectName, result.getETag());
            return true;
        } catch (Exception e) {
            log.error("上传对象到OSS失败: {} -> {}", sourceObjectName, targetObjectName, e);
            return false;
        }
    }
    
    /**
     * 检查对象是否存在
     * 
     * @param objectName 对象名称
     * @return 对象是否存在
     */
    public boolean doesObjectExist(String objectName) {
        checkClientAvailable();
        try {
            return ossClient.get().doesObjectExist(ossProperties.getBucketName(), objectName);
        } catch (Exception e) {
            log.error("检查OSS对象是否存在失败: {}", objectName, e);
            return false;
        }
    }
    
    /**
     * 检查存储桶是否存在
     * 
     * @return 存储桶是否存在
     */
    public boolean doesBucketExist() {
        checkClientAvailable();
        try {
            return ossClient.get().doesBucketExist(ossProperties.getBucketName());
        } catch (Exception e) {
            log.error("检查OSS存储桶是否存在失败", e);
            return false;
        }
    }
    
    /**
     * 根据文件名检测Content-Type
     * 
     * @param objectName 对象名称
     * @return Content-Type
     */
    private String detectContentType(String objectName) {
        try {
            String contentType = tika.detect(objectName);
            return contentType != null ? contentType : "application/octet-stream";
        } catch (Exception e) {
            log.warn("检测文件类型失败: {}，使用默认类型", objectName);
            return "application/octet-stream";
        }
    }
}